using System.Data;
using ScrumTable.Common;
using ScrumTable.Common.Excel.OpenXmlSdk.Extensions;

namespace ScrumTable.DL.Data.Excel.Services.Excel
{
    /// <summary>
    /// Defines a class to map a schema to a excel sheet.
    /// </summary>
    internal class SheetMapping
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private readonly DataSet _workbook;
        private readonly string _sheetName;
        private readonly int _idSeed;
        private int _lastId;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Returns true if the current workbook instance contains a sheet with
        /// the given name.
        /// </summary>
        internal bool IsContained
        {
            get { return (_sheetName != null && _workbook.Tables.Contains(_sheetName)); }
        }

        /// <summary>
        /// Gets the 'to' property content.
        /// </summary>
        internal DataTable Sheet
        {
            get
            {
                if (IsContained)
                {
                    return _workbook.Tables[_sheetName];
                }
                return null;
            }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new WorkbookMapper instance.
        /// </summary>
        /// <param name="workbookData">Specifies the underlying data.</param>
        /// <param name="sheetName">Specifies the sheet name which maps the data from the a ScrumTable field to the Excel data.</param>
        /// <param name="idIncrementSeed">Specifies the start seed for the id increment algo.</param>
        internal SheetMapping(DataSet workbookData, string sheetName, int idIncrementSeed)
        {
            PreCondition.AssertNotNull(workbookData, "workbookData");

            _workbook = workbookData;
            _sheetName = sheetName;
            _lastId = idIncrementSeed;
            _idSeed = idIncrementSeed;
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        internal DataRow GetOrCreateDataRow(ref int elementId)
        {
            DataRow workItemRow;

            if (!TryGetById(elementId, out workItemRow))
            {
                elementId = GetNextIdValue();

                workItemRow = Sheet.NewRow();
                workItemRow.SetFirstPrimaryKey(elementId);
                Sheet.Rows.Add(workItemRow);
            }
            return workItemRow;
        }

        internal bool TryGetByRefId(string refId, out DataRow retrievedRow)
        {
            retrievedRow = null;

            if (!string.IsNullOrEmpty(refId) && TryGetById(RefIdConverter.FromRefId(refId), out retrievedRow))
            {
                return true;
            }
            return false;
        }

        internal bool TryGetById(int id, out DataRow retrievedRow)
        {
            retrievedRow = null;

            if (id != RefIdConverter.DefaultId && Sheet.TryGetRowById(id, out retrievedRow))
            {
                return true;
            }
            return false;
        }

        private int GetNextIdValue()
        {
            if (Sheet.Rows.Count == 0)
            {
                return _idSeed;
            }
            else
            {
                while (Sheet.ContainsRow(_lastId))
                {
                    ++_lastId;
                }
                return _lastId;
            }
        }

        #endregion
    }
}